<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <title>奉孝的测开日记</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  
  
  
    <link rel="alternate" href="/blog/atom.xml" title="奉孝的测开日记" type="application/atom+xml">
  
  
    <link rel="shortcut icon" href="/blog/favicon.png">
  
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-source-code-pro@0.0.71/index.min.css">

  
  
<link rel="stylesheet" href="/blog/css/style.css">

  
    
<link rel="stylesheet" href="/blog/fancybox/jquery.fancybox.min.css">

  
  
    
<link rel="stylesheet" href="/blog/localshare/css/share.css">

  
  
  
<meta name="generator" content="Hexo 5.4.2"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/blog/" id="logo">奉孝的测开日记</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="/blog/" id="subtitle">开启自我改变的原动力</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        
          <a class="main-nav-link" href="/blog/."><i class="fa fa-home"></i> 首页</a>
        
          <a class="main-nav-link" href="/blog/archives/"><i class="fa fa-archive"></i> 归档</a>
        
          <a class="main-nav-link" href="/blog/about/"><i class="fa fa-user"></i> 关于</a>
        
      </nav>
    </div>
    <div id="search-form">
      <div id="result-mask" class="hide"></div>
      <label><input id="search-key" type="text" autocomplete="off" placeholder="搜索"></label>
      <div id="result-wrap" class="hide">
        <div id="search-result"></div>
      </div>
      <div class="hide">
        <template id="search-tpl">
          <div class="item">
            <a href="/{path}" title="{title}">
              <div class="title">{title}</div>
              <div class="time">{date}</div>
              <div class="tags">{tags}</div>
            </a>
          </div>
        </template>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main">
  <article id="post-深入理解列表和元组" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2023-03-14T09:14:39.814Z" itemprop="datePublished">2023年03月14日</time>
</span>
      
      
      
<a href="/blog/2023/03/14/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E5%88%97%E8%A1%A8%E5%92%8C%E5%85%83%E7%BB%84/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="列表和元组基础"><a href="#列表和元组基础" class="headerlink" title="列表和元组基础"></a>列表和元组基础</h1><p><strong>基本概念</strong></p>
<p>一个可以放任意数据类型的有序集合。</p>
<p>Java编程中集合的数据类型必须一致，而Python就比较随意</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">l = [<span class="string">&quot;小红&quot;</span>, <span class="number">1</span>]</span><br><span class="line">tup = (<span class="string">&#x27;小红&#x27;</span>, <span class="number">1</span>)</span><br></pre></td></tr></table></figure>

<p><strong>区别</strong></p>
<ul>
<li>列表是动态的，长度大小不固定，可以随意地增加、删减或者改变元素</li>
<li>元组是静态的，长度大小固定，无法增加删减或者改变</li>
</ul>
<p><strong>相比Java便捷操作</strong></p>
<ul>
<li><p>支持负数索引，-1表示最后一个元素。Java用负数索引会报错</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java.lang.ArrayIndexOutOfBoundsException</span><br></pre></td></tr></table></figure></li>
<li><p>切片操作</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">l = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">l[<span class="number">0</span>:<span class="number">1</span>]</span><br></pre></td></tr></table></figure></li>
</ul>
<p><strong>常用内置函数</strong></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">l = [<span class="number">3</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">1</span>]</span><br><span class="line">l.count(<span class="number">3</span>) <span class="comment"># 2 item 出现的次数</span></span><br><span class="line"></span><br><span class="line">l.index(<span class="number">7</span>) <span class="comment"># 3 item 第一次出现的索引</span></span><br><span class="line"></span><br><span class="line">l.reverse() <span class="comment"># [1, 8, 7, 3, 2, 3] 原地倒转列表,元组没有此函数</span></span><br><span class="line"></span><br><span class="line">l.sort() <span class="comment"># [1, 2, 3, 3, 7, 8] 排序,元组没有此函数 </span></span><br><span class="line"></span><br><span class="line">tup = (<span class="number">3</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">1</span>)</span><br><span class="line">tup.count(<span class="number">3</span>)</span><br><span class="line"></span><br><span class="line">tup.index(<span class="number">7</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">list</span>(<span class="built_in">reversed</span>(tup)) <span class="comment"># [1, 8, 7, 3, 2, 3] 对列表/元组进行倒转，reversed()返回一个倒转后的迭代器（例子使用 list() 函数再将其转换为列表）</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sorted</span>(tup) <span class="comment"># [1, 2, 3, 3, 7, 8] 返回排好序的新列表</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h1 id="深入解析"><a href="#深入解析" class="headerlink" title="深入解析"></a>深入解析</h1><h2 id="python这么随意吗"><a href="#python这么随意吗" class="headerlink" title="python这么随意吗"></a>python这么随意吗</h2><p>基础模块中，提到同一个列表中可以存储不同数据类型的元素。</p>
<p>那么为什么Python可以如此随意呢？翻源码<a target="_blank" rel="noopener" href="https://github.com/python/cpython/blob/main/Include/cpython/listobject.h">https://github.com/python/cpython/blob/main/Include/cpython/listobject.h</a></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> _<span class="title">object</span> &#123;</span></span><br><span class="line">    _PyObject_HEAD_EXTRA  <span class="comment">/* 构造双向链表*/</span></span><br><span class="line">    Py_ssize_t ob_refcnt; <span class="comment">/* 引用计数器 */</span></span><br><span class="line">    PyTypeObject *ob_type;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">    PyObject ob_base;</span><br><span class="line">    Py_ssize_t ob_size; <span class="comment">/* 内部元素个数 */</span></span><br><span class="line">&#125; PyVarObject;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">    PyObject_VAR_HEAD</span><br><span class="line">    <span class="comment">/* 指向列表元素的指针向量.  list[0] is ob_item[0], etc. */</span></span><br><span class="line">    PyObject **ob_item;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* ob_item contains space for &#x27;allocated&#x27; elements.  The number</span></span><br><span class="line"><span class="comment">     * currently in use is ob_size.</span></span><br><span class="line"><span class="comment">     * Invariants:</span></span><br><span class="line"><span class="comment">     *     0 &lt;= ob_size &lt;= allocated</span></span><br><span class="line"><span class="comment">     *     len(list) == ob_size</span></span><br><span class="line"><span class="comment">     *     ob_item == NULL implies ob_size == allocated == 0</span></span><br><span class="line"><span class="comment">     * list.sort() temporarily sets allocated to -1 to detect mutations.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * Items must normally not be NULL, except during construction when</span></span><br><span class="line"><span class="comment">     * the list is not yet visible outside the function that builds it.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Py_ssize_t allocated;</span><br><span class="line">&#125; PyListObject;</span><br></pre></td></tr></table></figure>

<p>看源码知道，PyListObject结构体定义了类型为</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PyObject **</span><br></pre></td></tr></table></figure>

<p>的ob_item，指针指向了元素列表所在内存块的首地址。所以python的list并不直接保存元素，而是保存的指针，这也是list中可以同时存放多种类型元素的根本原因。</p>
<p>通俗点讲，列表和元组本质上可以看成是一个指针列表，里面存放了每个元素的地址，而这些地址指向的具体元素，类型和大小可能是不同的，正是这种机制实现了不同数据类型元素的存储，而存储的每个指针变量都占8字节，所以可以这么理解，本质上，每次插入元素大小是固定的，不管字符串、整型，因为存储的都是指针变量。</p>
<h2 id="列表和元组存储差异"><a href="#列表和元组存储差异" class="headerlink" title="列表和元组存储差异"></a>列表和元组存储差异</h2><p>基础模块中提到，列表是动态可变的，元组是静态不可变的，那么存储有何差异呢</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">l = []</span><br><span class="line">l.__sizeof__() #</span><br><span class="line"></span><br><span class="line">1、若直接购买正式会员（年卡、两年卡、分销1年赠1卡），不再展示 9.9元体验卡</span><br><span class="line">2、机构介绍机构，扫码后跳转到机构注册页</span><br><span class="line">3、机构介绍用户，扫码后跳转到9.9元支付页</span><br><span class="line">4、机构介绍机构，若无绑定关系则添加绑定关系</span><br><span class="line">5、同一个身份证号只能填写一次</span><br><span class="line">用户获得过会员时长之后不再绑定介绍关系（合伙人与用户之间）</span><br><span class="line"></span><br></pre></td></tr></table></figure>


        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-Java单元测试Mock神器" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2023/03/09/Java%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95Mock%E7%A5%9E%E5%99%A8/">Java单元测试Mock神器</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2023-03-09T10:00:48.000Z" itemprop="datePublished">2023年03月09日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/Java/">Java</a>
  </div>

      
      
<a href="/blog/2023/03/09/Java%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95Mock%E7%A5%9E%E5%99%A8/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="TestableMock简介"><a href="#TestableMock简介" class="headerlink" title="TestableMock简介"></a>TestableMock简介</h1><p>官方介绍”一款特立独行的轻量Mock工具，以<strong>简化Java单元测试</strong>为目标的综合辅助工具集”</p>
<h1 id="Maven项目中使用"><a href="#Maven项目中使用" class="headerlink" title="Maven项目中使用"></a>Maven项目中使用</h1><p>在<strong>dependencies</strong>列表添加TestableMock依赖  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;com.alibaba.testable&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;testable-all&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;0.7.9&lt;/version&gt;</span><br><span class="line">    &lt;scope&gt;test&lt;/scope&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure>
<p>最后在<strong>build</strong>区域的<strong>plugins</strong>列表里添加<strong>maven-surefire-plugin</strong>插件  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;plugin&gt;</span><br><span class="line">    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;</span><br><span class="line">    &lt;configuration&gt;</span><br><span class="line">        &lt;argLine&gt;-javaagent:$&#123;settings.localRepository&#125;/com/alibaba/testable/testable-agent/0.7.9/testable-agent-0.7.9.jar&lt;/argLine&gt;</span><br><span class="line">    &lt;/configuration&gt;</span><br><span class="line">&lt;/plugin&gt;</span><br></pre></td></tr></table></figure>

<h1 id="TestableMock可以Mock什么"><a href="#TestableMock可以Mock什么" class="headerlink" title="TestableMock可以Mock什么"></a>TestableMock可以Mock什么</h1><h2 id="快速Mock任意调用"><a href="#快速Mock任意调用" class="headerlink" title="快速Mock任意调用"></a>快速Mock任意调用</h2><p>官方介绍”使被测类的任意方法调用快速替换为Mock方法，实现”指哪换哪”，解决传统Mock工具使用繁琐的问题”<br><strong>使用场景</strong><br>项目中有支付回调的场景，需要测试回调的方法逻辑是否正确。<br><strong>痛点</strong><br>方法中有调用其他jar包中的方法，而且该方法中还有很多逻辑，但这些逻辑并不是我们关注的<br><strong>解决</strong><br>待测方法  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">public String parseOrderNotifyResult(String xmlData) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">        WxPayOrderNotifyResult notifyResult = wxStudentMiniPayService.parseOrderNotifyResult(xmlData);</span><br><span class="line">    ...</span><br><span class="line">    ...</span><br></pre></td></tr></table></figure>
<p>wxStudentMiniPayService.parseOrderNotifyResult(xmlData)<br>该方法为maven引入jar包中的方法，我们的目的就是Mock该方法，从而只关注<br>待测方法的逻辑<br>测试case,直接看代码  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">@SpringBootTest</span><br><span class="line">public class PayServiceImplTest extends AbstractTestNGSpringContextTests &#123;</span><br><span class="line"></span><br><span class="line">    @Resource</span><br><span class="line">    private PayServiceImpl payService;</span><br><span class="line">    </span><br><span class="line">    public static class Mock&#123;</span><br><span class="line">        @MockInvoke(targetClass = WxPayService.class)</span><br><span class="line">        public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) &#123;</span><br><span class="line">            WxPayOrderNotifyResult wxPayOrderNotifyResult = new WxPayOrderNotifyResult();</span><br><span class="line">            wxPayOrderNotifyResult.setTransactionId(&quot;11111&quot;);</span><br><span class="line">            wxPayOrderNotifyResult.setResultCode(&quot;SUCCESS&quot;);</span><br><span class="line">            wxPayOrderNotifyResult.setOutTradeNo(&quot;74afe6ab214248b49898a832da79b742&quot;);</span><br><span class="line">            wxPayOrderNotifyResult.setDeviceInfo(&quot;KLASS&quot;);</span><br><span class="line">            return wxPayOrderNotifyResult;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Test(description = &quot;支付回调&quot;)</span><br><span class="line">    public void testParseOrderNotifyResult()&#123;</span><br><span class="line">        String xmlData = &quot;&quot;;</span><br><span class="line">        String res = payService.parseOrderNotifyResult(xmlData);</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p>此时，执行测试case，待测方法中<code>WxPayOrderNotifyResult notifyResult = wxStudentMiniPayService.parseOrderNotifyResult(xmlData)</code><br>notifyResult返回的结果就是Mock容器中对应的数据。<br>上面代码，就是在测试类中添加了一个名称为Mock的静态内部类，拷贝原方法定义到Mock容器类，加@MockInvoke注解。这也是官方推荐的最简单的做法  </p>
<h2 id="访问被测类私有成员"><a href="#访问被测类私有成员" class="headerlink" title="访问被测类私有成员"></a>访问被测类私有成员</h2><p>TestableMock提供了PrivateAccessor工具类</p>
<h3 id="访问私有方法"><a href="#访问私有方法" class="headerlink" title="访问私有方法"></a>访问私有方法</h3><p>PrivateAccessor.invoke(任意对象, “私有方法名”, 调用参数…) ➜ 调用任意类的私有方法<br><strong>使用场景</strong><br>通过公有方法间接测私有方法比较繁琐，公有方法有复杂的入参，核心业务逻辑在私有方法中，我们更加关注私有方法的业务逻辑。<br><strong>痛点</strong><br>未使用TestableMock时，我是修改了方法的可见性，private变为public，这种方法比较繁琐<br><strong>解决</strong><br>待测方法  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">private Student register(Map&lt;String, String&gt; paramMap) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如何借助PrivateAccessor测试该私有方法呢？  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">@Test(description = &quot;团购入口注册&quot;)</span><br><span class="line">public void registerTest() &#123;</span><br><span class="line">    Map&lt;String, String&gt; paramMap = new HashMap&lt;String, String&gt;()&#123;</span><br><span class="line">        &#123;</span><br><span class="line">            put(&quot;areaCode&quot;, &quot;86&quot;);</span><br><span class="line">            put(&quot;mobile&quot;, &quot;19900000007&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    Student student = PrivateAccessor.invoke(groupService, &quot;register&quot;, paramMap);</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>除了访问私有方法，还读取私有字段、修改私有字段、读取静态私有字段、修改静态私有字段、调用静态私有方法、调用私有构造方法，目前还未在单元测试</p>
<h3 id="修改私有字段"><a href="#修改私有字段" class="headerlink" title="修改私有字段"></a>修改私有字段</h3><p>PrivateAccessor.set(任意对象, “私有字段名”, 新的值)</p>
<p><strong>使用场景</strong></p>
<p>修改私有字段值，达到测试某种逻辑，比如下面待测方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">ENV_DEV</span> <span class="operator">=</span> <span class="string">&quot;dev&quot;</span>;</span><br><span class="line"><span class="meta">@Value(&quot;$&#123;spring.profiles.active&#125;&quot;)</span></span><br><span class="line"><span class="keyword">private</span> String env;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> Pair&lt;Integer, Integer&gt; <span class="title function_">sourceAndRealCommission</span><span class="params">(Byte direct, Integer product, <span class="type">boolean</span> isTest)</span> &#123;</span><br><span class="line">        ...</span><br><span class="line">        Table&lt;Byte, Integer, Integer&gt; commissionMap = TYPE_PRODUCT_COMMISSION_MAP;</span><br><span class="line">        <span class="keyword">if</span> (isTest || Objects.equals(ENV_DEV, env)) &#123;</span><br><span class="line">            commissionMap = TEST_TYPE_PRODUCT_COMMISSION_MAP;</span><br><span class="line">        &#125;</span><br><span class="line">  			...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>正常测试环境，必然会走if逻辑中的代码，ENV_DEV为常量值，env在测试环境值为dev，想要if条件变为false，将代码中的常量ENV_DEV的值变为prd，或者将启动环境变为非测试环境，这种方法显然不灵活，但是PrivateAccessor就可以不改源码，轻松做到</p>
<p>测试方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test(description = &quot;获取购买不同产品，返现的金额。&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sourceAndRealCommissionTest</span><span class="params">()</span>&#123;</span><br><span class="line">        ...</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">isTest</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">        PrivateAccessor.set(commissionService, <span class="string">&quot;env&quot;</span>, <span class="string">&quot;prd&quot;</span>);</span><br><span class="line">        ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>也可以更改ENV_DEV的值，但不建议，static final修饰的成员变量通常代表恒定常量值，不应该在单元测试中修改。确实要改，TestableMock也提供了解决方案，可以看官方文档。</p>
<h2 id="快速构造参数对象"><a href="#快速构造参数对象" class="headerlink" title="快速构造参数对象"></a>快速构造参数对象</h2><p><strong>使用场景</strong></p>
<p>被测方法需要有复杂的入参</p>
<p>被测方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> String <span class="title function_">fetchCipher</span><span class="params">(HttpServletResponse response)</span> &#123;</span><br><span class="line">        ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们使用OmniConstructor快速构造入参，测试方法如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test(description = &quot;获取签名需要使用的key&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">fetchCipherTest</span><span class="params">()</span>&#123;</span><br><span class="line">       <span class="type">HttpServletResponse</span> <span class="variable">response</span> <span class="operator">=</span> OmniConstructor.newInstance(HttpServletResponse.class);</span><br><span class="line">       <span class="type">String</span> <span class="variable">res</span> <span class="operator">=</span> loginService.fetchCipher(response);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h2 id="辅助测试void方法"><a href="#辅助测试void方法" class="headerlink" title="辅助测试void方法"></a>辅助测试void方法</h2>
        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/" rel="tag">单元测试</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-Pytest执行用例的多种方式" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2023/02/21/Pytest%E6%89%A7%E8%A1%8C%E7%94%A8%E4%BE%8B%E7%9A%84%E5%A4%9A%E7%A7%8D%E6%96%B9%E5%BC%8F/">Pytest执行用例的多种方式</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2023-02-21T05:51:09.000Z" itemprop="datePublished">2023年02月21日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/%E6%B5%8B%E8%AF%95/">测试</a>
  </div>

      
      
<a href="/blog/2023/02/21/Pytest%E6%89%A7%E8%A1%8C%E7%94%A8%E4%BE%8B%E7%9A%84%E5%A4%9A%E7%A7%8D%E6%96%B9%E5%BC%8F/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="一-、多种运行方式"><a href="#一-、多种运行方式" class="headerlink" title="一 、多种运行方式"></a>一 、多种运行方式</h1><h2 id="1-1-IDE运行"><a href="#1-1-IDE运行" class="headerlink" title="1.1 IDE运行"></a>1.1 IDE运行</h2><p>1、Pycharm运行方式配置，Tools-&gt;Python Integrated Tools-&gt;Testing 选择pytest<br>2、点击用例前面的绿色箭头运行</p>
<h2 id="1-2-命令行运行"><a href="#1-2-命令行运行" class="headerlink" title="1.2 命令行运行"></a>1.2 命令行运行</h2><p><strong>语法</strong>  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pytest 【运行参数】 【指定用例】</span><br><span class="line">#如pytest -s -v test_demo.py</span><br></pre></td></tr></table></figure>
<p><strong>运行参数</strong>  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">pytest -s test_demo.py                                         #显示代码中的print或日志打印</span><br><span class="line">pytest -v test_demo.py                                         #显示用例详情</span><br><span class="line">pytest -q test_demo.py                                         #简化显示，与-v相反</span><br><span class="line">pytest --collect-only  test_demo.py                            #检查哪些测试用例会被运行</span><br><span class="line">pytest -k &quot;not 02&quot; test_demo.py                                #选择用例运行,可以用not,or</span><br><span class="line">pytest -x test_demo.py                                         #遇到失败用例自动停止运行</span><br><span class="line">pytest --maxfail=2 test_demo.py                                #达到最大失败数自动停止运行</span><br><span class="line">pytest --tb=short test_demo.py                                 #失败信息的显示方式,三个固定值short : 仅输出assert 的一行以及系统判定的内容；line : 只使用一行输出显示所有的错误信息；no : 屏蔽所有的回溯信息</span><br><span class="line">pytest -m &quot;markname&quot; test_demo.py                              #指定标签名运行，配合mark标签装饰器</span><br><span class="line">pytest -n 3 test_demo.py                                       #分布式运行，指定3个进程，配合前面讲的xdist插件</span><br><span class="line">pytest --reruns 3 --reruns-delay 1 test_demo.py                #失败重复运行3次，每次1s间隔，配合pytest-rerunfailures插件</span><br><span class="line">pytest --html=report.html --self-contained-html test_demo.py   #输出测试报告，配合pytest-html插件</span><br><span class="line">pytest --alluredir ./result/ test_demo.py                      #输出allure报告数据到result目录，配合allure-pytest插件</span><br><span class="line">```  </span><br><span class="line">**指定用例**  </span><br></pre></td></tr></table></figure>
<p>pytest -s testsuit/                                            #指定文件夹下所有用例运行<br>pytest -s testsuit/test_demo.py                                #指定测试文件所有用例运行<br>pytest -s testsuit/test_demo.py::TestCase                      #指定测试类的所有用例运行，文件内用::连接<br>pytest -s testsuit/test_demo.py::TestCase::test_case_01        #指定单个测试用的所有用例运行</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">## 1.3 main函数运行</span><br><span class="line">**语法**  </span><br></pre></td></tr></table></figure>
<p>pytest.main(args=None, plugins=None)  #传参数列表，如[‘-s’,’test_demo.py’]</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">**参数**  </span><br><span class="line">* args: 运行测试的一些参数，和命令行运行时的参数相同，在列表 List 里以字符串 str 的形式，多参数以 “,” 隔开，也可以传入测试case的路径</span><br><span class="line">* plugins: 插件参数，也是列表形式，是运行 pytest 时运行下载的插件的参数。</span><br><span class="line"></span><br><span class="line">## 1.4 通过pytest.ini运行</span><br><span class="line">**示例**  </span><br></pre></td></tr></table></figure>
<p>[pytest]<br>addopts = “-vs”   #加不加引号都可以<br>testpaths = “./test_case”<br>python_files = “test*.py”<br>python_classes = “Test”<br>python_functions = “test”<br>markers =<br>    smoke:冒烟测试用例<br>    usermanage:用户管理模块测试用例</p>
<p>```  </p>
<ul>
<li><p>addopts<br>作用：主要用来配置运行用例时，需要的参数<br>示例：pytest -vs。我们可以把执行参数写到pytest.ini里面这样写：addopts = -vs</p>
</li>
<li><p>testpaths<br>作用：配置默认读取执行的项目路径<br>示例：pytest ./test_case。我们可以把执行参数写到pytest.ini里面这样写：testpaths = ./test_case</p>
</li>
<li><p>python_files<br>作用：模块的命名规则，pytest默认查找的模块是以test开头或结尾的。可以更改此规则。<br>示例：python_files = qqq*.py。默认搜索以qqq开头的模块</p>
</li>
<li><p>python_classes<br>作用：类的命名规则，pytest默认查找的类是以Test开头的。可以更改此规则。<br>示例：python_class = qqq。默认搜索以qqq开头的类</p>
</li>
<li><p>python_functions<br>作用：方法的命名规则，pytest默认查找的方法是以test开头的。可以更改此规则。<br>示例：python_functions = qqq。默认搜索以qqq开头的方法</p>
</li>
<li><p>markers<br>作用：用例分组管理，贴标签。<br>在pytest.ini里面配置markers。然后测试类或测试用例前使用装饰器@pytest.mark.smoke，执行时使用pytest -m “smoke” ，即可执行特定标签的用例啦<br>查看标记：pytest –markers</p>
</li>
<li><p>norecursedirs<br>作用：搜索时忽略目录。norecurse的默认设置是  .*  build  dist CVS -darcs {arch} 和 *.egg。因为有  .*，所以将虚拟环境命名为.venv是一个好注意，所有以.(点)开头的目录都不会被访问。如果不是以.(点)开头，那么需要把它加入norecursedirs里。</p>
</li>
</ul>
<p>示例：比如我想忽略page目录，norecursedirs = .*  build  dist CVS -darcs {arch} *.egg page</p>
<ul>
<li><p>xfail_strict<br>作用：设置xfail_strict=True将会使那些被标记为@pytest.mark.xfail但实际通过的测试用例也被报告为失败</p>
</li>
<li><p>minversion<br>作用：指定运行测试用例的pytest的最低版本。<br>示例：minversion = 4.0。当pytest版本小于此时4.0时，会报错</p>
</li>
<li><p>cache_dir<br>作用：设置cache目录, 默认.pytest_cache<br>示例：cache_dir = ./cache</p>
</li>
<li><p>pythonpath<br>作用：添加路径到sys.path</p>
</li>
<li><p>required_plugins<br>作用：设置哪些插件在运行pytest前必须安装好。</p>
</li>
</ul>

        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/" rel="tag">自动化</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-SQL查询场景" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2023/02/20/SQL%E6%9F%A5%E8%AF%A2%E5%9C%BA%E6%99%AF/">SQL查询场景</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2023-02-20T02:51:19.000Z" itemprop="datePublished">2023年02月20日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/%E5%90%8E%E7%AB%AF/">后端</a>
  </div>

      
      
<a href="/blog/2023/02/20/SQL%E6%9F%A5%E8%AF%A2%E5%9C%BA%E6%99%AF/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="一、工作中常遇到的场景"><a href="#一、工作中常遇到的场景" class="headerlink" title="一、工作中常遇到的场景"></a>一、工作中常遇到的场景</h1><h2 id="1-1-查询"><a href="#1-1-查询" class="headerlink" title="1.1 查询"></a>1.1 查询</h2><h3 id="1-1-1-查询重复记录"><a href="#1-1-1-查询重复记录" class="headerlink" title="1.1.1 查询重复记录"></a>1.1.1 查询重复记录</h3><p><strong>思路</strong><br>1、查看重复记录，首先要使用分组函数（group by），再用聚合函数中的计数函数count(name)给姓名列计数<br>2、查关键字：姓名，以姓名进行分组，看潜在条件：重复，也就是count（name）&gt;1，使用having过滤条件</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># 方式一</span><br><span class="line">select name, count(*) from books group by name having count(name) &gt; 1;</span><br><span class="line"></span><br><span class="line"># 方式二(推荐)</span><br><span class="line">select name, count(*) as c from books group by name having c &gt; 1;</span><br></pre></td></tr></table></figure>

        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/MySQL/" rel="tag">MySQL</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-MySQL命令手册" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2023/01/18/MySQL%E5%91%BD%E4%BB%A4%E6%89%8B%E5%86%8C/">MySQL命令手册</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2023-01-18T08:16:14.000Z" itemprop="datePublished">2023年01月18日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/%E5%90%8E%E7%AB%AF/">后端</a>
  </div>

      
      
<a href="/blog/2023/01/18/MySQL%E5%91%BD%E4%BB%A4%E6%89%8B%E5%86%8C/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="一、基础操作与库命令"><a href="#一、基础操作与库命令" class="headerlink" title="一、基础操作与库命令"></a>一、基础操作与库命令</h1><h2 id="1-1、基础操作命令"><a href="#1-1、基础操作命令" class="headerlink" title="1.1、基础操作命令"></a>1.1、基础操作命令</h2><ul>
<li>启动MySQL服务<ul>
<li>windows <code>net start mysql</code></li>
<li>linux <code>安装目录/mysql start</code><ul>
<li>shutdown 关闭服务</li>
<li>restart 重启</li>
</ul>
</li>
</ul>
</li>
<li>查看进程 <code>ps -ef | grep mysql</code></li>
<li>强杀MySQL服务 <code>kill -9 MySQL进程ID</code></li>
<li>客户端连接MySQL服务 <code>mysql -h地址 -p端口 -u账号 -p</code></li>
<li>查看MySQL运行状态 <code>show status;</code></li>
<li>查看当前库中正在运行的所有客户端连接/工作线程 <code>show processlist;</code></li>
<li>查看当前版本MySQL支持的所有数据类型 <code>help data types;</code></li>
<li>退出当前数据库连接 <code>quit</code><h2 id="1-2、库命令"><a href="#1-2、库命令" class="headerlink" title="1.2、库命令"></a>1.2、库命令</h2></li>
<li>目前MySQL中拥有的所有库<code>show databases;</code></li>
<li>查看当前数据库支持的所有存储引擎<code>show engines;</code></li>
<li>指定的某个数据库<code>use 库名;</code></li>
<li>当前数据库的状态信息<code>show status;</code></li>
<li>当前连接的权限信息<code>show grants;</code></li>
<li>当前库中记录的错误信息<code>show errors;</code></li>
<li>当前库抛出的所有警告信息<code>show warnings;</code></li>
<li>查看创建某个库的SQL详细信息<code>show create database 库名;</code></li>
<li>查看创建某张表的SQL详细信息<code>show create table 表名;</code></li>
<li>查看一个库中的所有表<code>show tables;</code></li>
<li>查看一张表的字段结构<code>desc 表名;</code></li>
<li>新建一个数据库<code>create database 库名;</code></li>
<li>删除一个数据库<code>drop database 库名;</code></li>
<li>修改数据库的编码格式、排序规则<code>ALTER DATABASE 库名 DEFAULT CHARACTER SET 编码格式 DEFAULT COLLATE 排序规则</code></li>
</ul>

        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/MySQL/" rel="tag">MySQL</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-TestNG基础" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2022/11/01/TestNG%E5%9F%BA%E7%A1%80/">TestNG基础</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2022-11-01T10:16:18.000Z" itemprop="datePublished">2022年11月01日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/%E6%B5%8B%E8%AF%95%E8%BF%9B%E9%98%B6/">测试进阶</a>
  </div>

      
      
<a href="/blog/2022/11/01/TestNG%E5%9F%BA%E7%A1%80/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="注解"><a href="#注解" class="headerlink" title="注解"></a>注解</h1><ul>
<li>@BeforeSuite 所有测试运行之前</li>
<li>@AfterSuite 所有测试运行之后</li>
<li>@BeforeTest</li>
<li>@AfterTest</li>
<li>@BeforeGroups</li>
<li>@AfterGroups</li>
<li>@BeforeClass</li>
<li>@AfterClass</li>
<li>@BeforeMethod</li>
<li>@AfterMethod</li>
</ul>
<h1 id="多线程并行测试用例"><a href="#多线程并行测试用例" class="headerlink" title="多线程并行测试用例"></a>多线程并行测试用例</h1><p>可以给@Test添加属性，让用例以多线程并行执行：  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">@Test(threadPoolSize = 3, invocationCount = 10,  timeOut = 10000)</span><br><span class="line">public void testServer() &#123;</span><br></pre></td></tr></table></figure>
<ul>
<li>threadPoolSize指3个线程</li>
<li>invocationCount指运行10次</li>
<li>timeOut指阻塞等待超时</li>
</ul>
<p>也可以在testng.xml中设置，thread-count指定线程数，parallel设置不同的值有不同的含义：<br>methods:  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;suite name=&quot;My suite&quot; parallel=&quot;methods&quot; thread-count=&quot;5&quot;&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>所有测试方法在不同的独立线程中执行。  </p>
<p>tests:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;suite name=&quot;My suite&quot; parallel=&quot;tests&quot; thread-count=&quot;5&quot;&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p><test>标签内的测试方法会在同一个线程中执行，不同的<test>标签会在不同的独立线程中执行。  </p>
<p>classes:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;suite name=&quot;My suite&quot; parallel=&quot;classes&quot; thread-count=&quot;5&quot;&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>同一个类中的测试方法会在同一个线程中执行，不同的类会在不同的独立线程中执行。  </p>
<p>instances:</p>
<figure class="highlight plaintext"><figcaption><span>name</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>
<p>同一个实例中的测试方法会在同一个线程中执行，不同的实例会在不同的独立线程中执行</p>

        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/" rel="tag">学习总结</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-vim必会命令" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2022/10/17/vim%E5%BF%85%E4%BC%9A%E5%91%BD%E4%BB%A4/">vim必会命令</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2022-10-17T07:52:00.000Z" itemprop="datePublished">2022年10月17日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/vim/">vim</a>
  </div>

      
      
<a href="/blog/2022/10/17/vim%E5%BF%85%E4%BC%9A%E5%91%BD%E4%BB%A4/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="中文文档"><a href="#中文文档" class="headerlink" title="中文文档"></a>中文文档</h1><p>以mac环境为例  </p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">cd ~/.vim // 如果没有文件夹就自己创建一个</span><br><span class="line">mkdir -p pack/my/start</span><br><span class="line">git clone https://github.com/yianwillis/vimcdoc.git pack/my/start/vimcdoc</span><br><span class="line">```  </span><br><span class="line">Vim 教程支持多语言，可使用命令 vimtutor 来启动。如果启动的教程的语言不是你希望的，</span><br><span class="line">你可以使用环境变量 LANG 来设定希望的语言   </span><br><span class="line">```shell</span><br><span class="line">LANG=zh_CN.UTF-8 vimtutor</span><br></pre></td></tr></table></figure>

<h1 id="基础命令"><a href="#基础命令" class="headerlink" title="基础命令"></a>基础命令</h1><h2 id="移动"><a href="#移动" class="headerlink" title="移动"></a>移动</h2><ul>
<li>h 左</li>
<li>l 右</li>
<li>j 下</li>
<li>k 上</li>
<li>w 从关标处移动至下一个单词的起始处</li>
<li>2w 移动2个单词</li>
<li>e 从关标处移动至该单词的末尾</li>
<li>3e 使光标向前移动到第三个单词的末尾</li>
<li>0 移动光标到行首</li>
<li>$ 移动光标到行尾</li>
<li>( 和 ) 移到上一句和下一句</li>
<li>{ 和 } 移到上一段和下一段</li>
<li>control-f  向下翻页</li>
<li>control-b  向上翻页</li>
<li>control-d  向下翻半页</li>
<li>control-u  向上翻半页</li>
<li>control-e   光标不动，向上滚动屏幕</li>
<li>control-y   光标不动，向下滚动屏幕</li>
<li>zt  鼠标所在当前行滚到屏幕顶部</li>
<li>zz  鼠标所在当前行滚到屏幕中部</li>
<li>zb  鼠标所在当前行滚到屏幕底部</li>
</ul>
<h2 id="替换"><a href="#替换" class="headerlink" title="替换"></a>替换</h2><ul>
<li>S 替换行</li>
<li>s 替换字符</li>
<li>r 输入 r 和一个字符替换光标所在位置的字符</li>
<li>R 可连续替换多个字符, R 将进入替换模式，直至按 <ESC> 键回到正常模式</li>
<li>:s/old/new  可以替换old为new,只改变光标所在行的第一个匹配串</li>
<li>:s/old/new/g  可以替换old为new,替换全行的匹配串</li>
<li>:%s/old/new/g  替换整个文件中的每个匹配串</li>
<li>:%s/old/new/gc 会找到整个文件中的每个匹配串，并且对每个匹配串提示是否进行替换</li>
<li>:#,#s/old/new/g 替换两行之间出现的每个匹配串，#,#代表行号</li>
</ul>
<h2 id="添加"><a href="#添加" class="headerlink" title="添加"></a>添加</h2><ul>
<li>A 在一行后添加文本</li>
<li>a 光标字符后添加文本</li>
<li>i 光标字符前添加文本</li>
<li>o  在光标 <strong>下方</strong> 打开新的一行，这个命令会使您进入插入模式</li>
<li>O  在光标 <strong>上方</strong> 打开新的一行，这个命令会使您进入插入模式</li>
</ul>
<h2 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h2><ul>
<li>D 当前行，删除光标以及光标后的</li>
<li>dd 删除当前行</li>
<li>d2d 从当前行开始，删除2行</li>
<li>dw 从关标处删除至下一个单词的起始处</li>
<li>d2w 删除2个单词</li>
<li>de 从关标处删除至单词末尾</li>
<li>d$ 从当前关标删除到行末</li>
<li>x 删除当前字符</li>
<li>X 删除关标所在位置的前一个字符<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">if (message == &quot;sesame open&quot;)</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">假设关标在sesame的a上</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">dw（理解为 delete word） 删除<span class="string">&#x27;ame␣&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">diw（理解为 delete inside word） 删除<span class="string">&#x27;sesame&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">daw（理解为 delete a word） 删除<span class="string">&#x27;sesame␣&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">diW 会删除<span class="string">&#x27;&quot;sesame&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">daW 会删除<span class="string">&#x27;&quot;sesame␣&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">di<span class="string">&quot; 会删除&#x27;sesame open&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash"><span class="string">da&quot;</span> 会删除<span class="string">&#x27;&quot;sesame open&quot;&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">di( 或 di) 会删除<span class="string">&#x27;message == &quot;sesame open&quot;&#x27;</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">da( 或 da) 会删除<span class="string">&#x27;(message == &quot;sesame open&quot;)&#x27;</span></span></span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="跳转定位"><a href="#跳转定位" class="headerlink" title="跳转定位"></a>跳转定位</h2><ul>
<li>G 跳转到结尾</li>
<li>gg 跳转到开头</li>
<li>ctrl-g   显示当前编辑文件中当前光标所在行位置以及文件状态信息</li>
<li>5G 定位到第5行</li>
<li>5| 定位到第5列</li>
<li>vim -c ‘normal 5G5|’ text.txt   直接定位到第5行第5列</li>
</ul>
<h2 id="修改"><a href="#修改" class="headerlink" title="修改"></a>修改</h2><ul>
<li>C 则相当于 c$，删除到行尾然后进入插入模式。</li>
<li>c 加动作来进行修改（cc 修改整行）</li>
</ul>
<h2 id="选择"><a href="#选择" class="headerlink" title="选择"></a>选择</h2><ul>
<li>V 选择行</li>
<li>v 选择字符</li>
</ul>
<h2 id="撤销"><a href="#撤销" class="headerlink" title="撤销"></a>撤销</h2><ul>
<li>u 撤销最后执行的命令</li>
<li>U 撤消在最后一行中所做的改动</li>
<li>ctrl-r(先按下ctrl键，接着按r键) 撤消掉撤消命令</li>
</ul>
<h2 id="复制"><a href="#复制" class="headerlink" title="复制"></a>复制</h2><ul>
<li>使用操作符 y 复制文本，使用 p 粘贴文本(v选中，y复制，p粘贴)</li>
<li>y 当作操作符来使用。例如:yw 可以用来复制一个单词</li>
</ul>
<h2 id="粘贴"><a href="#粘贴" class="headerlink" title="粘贴"></a>粘贴</h2><ul>
<li>p 最后一次删除的内容置入光标所在行的下一行(比如：先dd，然后输入p，粘贴)</li>
</ul>
<h2 id="修改-1"><a href="#修改-1" class="headerlink" title="修改"></a>修改</h2><ul>
<li>ce 改变文本直到一个单词的末尾</li>
</ul>
<h2 id="搜索"><a href="#搜索" class="headerlink" title="搜索"></a>搜索</h2><ul>
<li>/  输入 / 加上一个字符串可以用以在当前文件中查找该字符串</li>
<li>n 向下寻找</li>
<li>N 向上寻找</li>
<li>?代替/ 逆向查找，这样n就是向上寻找</li>
<li>ctrl-o 回退到之前的位置</li>
<li>ctrl-i 回到较新的位置</li>
<li>% 可以查找配对的括号 )、]、}  比如光标放在(，然后按%<h3 id="忽略大小写查找"><a href="#忽略大小写查找" class="headerlink" title="忽略大小写查找"></a>忽略大小写查找</h3></li>
<li>:set ic   Ignore Case，忽略大小写</li>
<li>:set hls is <ul>
<li>‘ic’ ‘ignorecase’       查找时忽略字母大小写</li>
<li>‘is’ ‘incsearch’        查找短语时显示部分匹配</li>
<li>‘hls’ ‘hlsearch’        高亮显示所有的匹配短语</li>
</ul>
</li>
<li>在选项前加上 no 可以关闭选项   比如  :set noic  禁用忽略大小写</li>
</ul>
<h2 id="在vim内执行外部命令"><a href="#在vim内执行外部命令" class="headerlink" title="在vim内执行外部命令"></a>在vim内执行外部命令</h2><ul>
<li>:!然后紧接着输入一个外部命领，比如:!ls -la</li>
</ul>
<h2 id="保存文件"><a href="#保存文件" class="headerlink" title="保存文件"></a>保存文件</h2><ul>
<li>:w FILENAME  将对文件的改动保存到新文件中，以 FILENAMEj 为文件名保存整个文件</li>
<li>选择性保存 先按V，上下移动，选中，然后按:  再输入w FILENAME</li>
</ul>
<h2 id="提取和合并文件"><a href="#提取和合并文件" class="headerlink" title="提取和合并文件"></a>提取和合并文件</h2><ul>
<li>光标放置待插入位置，输入: FILENAME(这是文件名)，就会把FILENAME中的内容提取到光标处</li>
<li>提取外部命令的输出。比如：:r !ls 可以读取 ls 命令的输出，并把它放置在光标下面</li>
</ul>
<h2 id="打开新的一行输入"><a href="#打开新的一行输入" class="headerlink" title="打开新的一行输入"></a>打开新的一行输入</h2><ul>
<li>o  在光标 <strong>下方</strong> 打开新的一行，这个命令会使您进入插入模式</li>
<li>O  在光标 <strong>上方</strong> 打开新的一行，这个命令会使您进入插入模式</li>
</ul>
<h2 id="命令补全"><a href="#命令补全" class="headerlink" title="命令补全"></a>命令补全</h2><ul>
<li>使用 CTRL-D 和 <TAB> 可以进行命令行补全。 当输入 : 命令时，按 CTRL-D 可以查看可能的补全结果</li>
</ul>
<h1 id="vimrc进阶配置"><a href="#vimrc进阶配置" class="headerlink" title=".vimrc进阶配置"></a>.vimrc进阶配置</h1><h2 id="基本配置"><a href="#基本配置" class="headerlink" title="基本配置"></a>基本配置</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">set enc=utf-8</span><br><span class="line">set nocompatible  # 关闭 vi 兼容模式</span><br><span class="line">source $VIMRUNTIME/vimrc_example.vim</span><br></pre></td></tr></table></figure>

<h2 id="备份和撤消文件"><a href="#备份和撤消文件" class="headerlink" title="备份和撤消文件"></a>备份和撤消文件</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">set nobackup</span><br><span class="line"></span><br><span class="line">if has(&#x27;persistent_undo&#x27;)</span><br><span class="line">  set undofile</span><br><span class="line">  set undodir=~/.vim/undodir</span><br><span class="line">  if !isdirectory(&amp;undodir)</span><br><span class="line">    call mkdir(&amp;undodir, &#x27;p&#x27;, 0700)</span><br><span class="line">  endif</span><br><span class="line">endif</span><br></pre></td></tr></table></figure>

<h2 id="鼠标支持"><a href="#鼠标支持" class="headerlink" title="鼠标支持"></a>鼠标支持</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">if has(&#x27;mouse&#x27;)</span><br><span class="line">  if has(&#x27;gui_running&#x27;) || (&amp;term =~ &#x27;xterm&#x27; &amp;&amp; !has(&#x27;mac&#x27;))</span><br><span class="line">    set mouse=a</span><br><span class="line">  else</span><br><span class="line">    set mouse=nvi</span><br><span class="line">  endif</span><br><span class="line">endif</span><br></pre></td></tr></table></figure>

<h2 id="中文支持"><a href="#中文支持" class="headerlink" title="中文支持"></a>中文支持</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set fileencodings=ucs-bom,utf-8,gb18030,latin1</span><br></pre></td></tr></table></figure>

<h2 id="字体配置"><a href="#字体配置" class="headerlink" title="字体配置"></a>字体配置</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">if has(&#x27;gui_running&#x27;)</span><br><span class="line">  set guifont=Courier_New:h11:cANSI</span><br><span class="line">  set guifontwide=新宋体:h11:cGB2312</span><br><span class="line">endif</span><br></pre></td></tr></table></figure>

<h2 id="只要屏幕能滚动，关标就无法移动到上面的4行和最下面4行"><a href="#只要屏幕能滚动，关标就无法移动到上面的4行和最下面4行" class="headerlink" title="只要屏幕能滚动，关标就无法移动到上面的4行和最下面4行"></a>只要屏幕能滚动，关标就无法移动到上面的4行和最下面4行</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash"><span class="built_in">set</span> scrolloff=5 会导致只要屏幕能滚动，关标就无法移动到上面的4行和最下面4行</span></span><br><span class="line">set scrolloff=1 # 可以减少干扰</span><br></pre></td></tr></table></figure>
<p>:</p>
<h2 id="minpac安装"><a href="#minpac安装" class="headerlink" title="minpac安装"></a>minpac安装</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://github.com/k-takata/minpac.git ~/.vim/pack/minpac/opt/minpac</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">if exists(&#x27;*minpac#init&#x27;)</span><br><span class="line"><span class="meta prompt_">  # </span><span class="language-bash">Minpac is loaded.</span></span><br><span class="line">  call minpac#init()</span><br><span class="line">  call minpac#add(&#x27;k-takata/minpac&#x27;, &#123;&#x27;type&#x27;: &#x27;opt&#x27;&#125;)</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">  # </span><span class="language-bash">Other plugins</span></span><br><span class="line">endif</span><br><span class="line"></span><br><span class="line">if has(&#x27;eval&#x27;)</span><br><span class="line"><span class="meta prompt_">  # </span><span class="language-bash">Minpac commands</span></span><br><span class="line">  command! PackUpdate packadd minpac | source $MYVIMRC | call minpac#update(&#x27;&#x27;, &#123;&#x27;do&#x27;: &#x27;call minpac#status()&#x27;&#125;)</span><br><span class="line">  command! PackClean  packadd minpac | source $MYVIMRC | call minpac#clean()</span><br><span class="line">  command! PackStatus packadd minpac | source $MYVIMRC | call minpac#status()</span><br><span class="line">endif</span><br></pre></td></tr></table></figure>

<h2 id="最近使用的文件"><a href="#最近使用的文件" class="headerlink" title="最近使用的文件"></a>最近使用的文件</h2><p>安装插件，然后执行:PackUpdate    </p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Other plugins</span></span><br><span class="line">call minpac#add(&#x27;yegappan/mru&#x27;)</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">if !has(&#x27;gui_running&#x27;)</span><br><span class="line">  &quot; 设置文本菜单</span><br><span class="line">  if has(&#x27;wildmenu&#x27;)</span><br><span class="line">    set wildmenu</span><br><span class="line">    set cpoptions-=&lt;</span><br><span class="line">    set wildcharm=&lt;C-Z&gt;</span><br><span class="line">    nnoremap &lt;F10&gt;      :emenu &lt;C-Z&gt;</span><br><span class="line">    inoremap &lt;F10&gt; &lt;C-O&gt;:emenu &lt;C-Z&gt;</span><br><span class="line">  endif</span><br><span class="line">endif</span><br></pre></td></tr></table></figure>
<p>输入 :emenu  再按tab就可以看到最近打开的文件</p>
<h2 id="已经存在交换文件"><a href="#已经存在交换文件" class="headerlink" title="已经存在交换文件"></a>已经存在交换文件</h2><p>错误提示<code>Swap file &quot;Desktop/logs/.text.txt.swp&quot; already exists!</code>，有两种原因：  </p>
<ol>
<li>上次编辑这个文件时，发生了意外崩溃</li>
<li>已经在使用另外一个vim会话编辑这个文件了<br>错误提示 process ID 后面没有”STILL RUNNING”这样的字样，就是情况1，其他就是情况2<br>针对情况1，可以<code>vim -r text.txt</code>恢复上次的编辑状态，确认之后，根据提示，删除交换文件。  </li>
</ol>
<h2 id="多文件打开的方式"><a href="#多文件打开的方式" class="headerlink" title="多文件打开的方式"></a>多文件打开的方式</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">vim *.txt *.log  # 暂时只打开第一个文件</span><br><span class="line"></span><br><span class="line">:args  要编辑的多文件列表</span><br><span class="line">:args *.xml  使用xml文件替换参数列表</span><br><span class="line">:next(:n)  打开下一个文件</span><br><span class="line">:Next(:N)或者:previous(:prev)  打开上一个文件</span><br><span class="line">:first  回到列表中的第一个文件</span><br><span class="line">:last   打开列表中的最后一个文件</span><br><span class="line"></span><br><span class="line">工作流：</span><br><span class="line">:set autowrite  告诉vim在切换文件时自动存盘</span><br><span class="line">:n|normal ggP   切换到下一个文件并执行正常模式命令ggP,跳转到文件开头并粘贴</span><br><span class="line">:向上箭头  执行上面的命令</span><br><span class="line"></span><br><span class="line">缓冲区：</span><br><span class="line">:ls  查看缓冲区列表（当前活跃%a  最近的缓冲区#  缓冲区已被修改+）</span><br><span class="line">:buffer(:b) 编号  跳转到编号对应的缓冲区。比如:b3  如果当前缓冲区已被修改但为保存，会报错，命令后加!会放弃修改，比如b!2 </span><br><span class="line">:bdelete(:bd) 编号  删除对应的缓冲区。:bd 8</span><br><span class="line">:bnext(:bn)  下一个</span><br><span class="line">:bprevious(:bp) 上一个</span><br><span class="line">:blast  最后一个</span><br><span class="line"></span><br><span class="line">control ^  最近的两个缓冲区之间来回切换</span><br></pre></td></tr></table></figure>

<h2 id="多窗口编辑"><a href="#多窗口编辑" class="headerlink" title="多窗口编辑"></a>多窗口编辑</h2><ul>
<li>水平分割<ul>
<li>:split(:sp) 当前窗口分隔开，当前编辑的文件在两个窗口里都显示</li>
<li>:split(:sp) 文件名 分割窗口并打开该文件</li>
</ul>
</li>
<li>竖直分割<ul>
<li>:vsplit(:vs)<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">control w w 跳转下一个窗口</span><br><span class="line">:new 或 control w n  打开新窗口</span><br><span class="line">:close 或 control w c 关闭当前窗口，最后一个无效</span><br><span class="line">:quit 或 control w q 退出当前窗口，最后一个则退出vim</span><br><span class="line">:only 或 control w o  只保留当前</span><br><span class="line">control w =   所有窗口大小相等</span><br><span class="line">control w 10_  设置高度为10</span><br><span class="line">control w 10|  设置宽度为10</span><br><span class="line">control w +  增加窗口高度，默认1</span><br><span class="line">control w -  减少窗口高度</span><br><span class="line">control w &gt;  增加窗口宽度</span><br></pre></td></tr></table></figure>
<h3 id="双窗口比较"><a href="#双窗口比较" class="headerlink" title="双窗口比较"></a>双窗口比较</h3></li>
</ul>
</li>
<li>vimdiff .vimrc ~/.vimrc</li>
</ul>
<h3 id="多标签页"><a href="#多标签页" class="headerlink" title="多标签页"></a>多标签页</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">:tabs  展示标签列表</span><br><span class="line">:tabnew 或 :tabedit 打开新的标签页。后跟文件名，新的标签打开这个文件</span><br><span class="line">:tabclose  关闭当前标签</span><br><span class="line">:tabnext 下一个标签页</span><br><span class="line">:tabprevious</span><br><span class="line">:tabfirst</span><br><span class="line">:tablast</span><br><span class="line">:control-w T 当前窗口变成一个新标签页</span><br></pre></td></tr></table></figure>

<h3 id="NERDTree插件"><a href="#NERDTree插件" class="headerlink" title="NERDTree插件"></a>NERDTree插件</h3><h4 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h4><p>.vimrc文件中增加  </p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">call minpac#add(&#x27;preservim/nerdtree&#x27;)</span><br></pre></td></tr></table></figure>
<p>然后执行<code>PackUpdate</code>,如果一直失败，也可以直接克隆<code>git clone https://github.com/preservim/nerdtree.git ~/.vim/pack/minpac/start/nerdtree</code>  </p>
<h4 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h4><ul>
<li>NERDTreeToggle  左侧打开文件浏览/管理窗口，也可以关闭</li>
<li>go  浏览文件，光标不会跳转到文件所在窗口</li>
<li>i   打开文件到新的水平分割窗口</li>
<li>s   打开文件到新的竖直分割窗口 </li>
<li>t   打开文件到新的标签页</li>
<li>m   出现菜单，可以添加、删除、更名</li>
<li>?  查看帮助信息</li>
</ul>
<h2 id="正则表达式：实现文件内容的搜索和替换"><a href="#正则表达式：实现文件内容的搜索和替换" class="headerlink" title="正则表达式：实现文件内容的搜索和替换"></a>正则表达式：实现文件内容的搜索和替换</h2>
        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/" rel="tag">学习总结</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-Java工具类和新语法" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2022/09/27/Java%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%92%8C%E6%96%B0%E8%AF%AD%E6%B3%95/">Java工具类和新语法</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2022-09-27T09:24:56.000Z" itemprop="datePublished">2022年09月27日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/Java/">Java</a>
  </div>

      
      
<a href="/blog/2022/09/27/Java%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%92%8C%E6%96%B0%E8%AF%AD%E6%B3%95/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="一、Collection类族"><a href="#一、Collection类族" class="headerlink" title="一、Collection类族"></a>一、Collection类族</h1><img src="/blog/2022/09/27/Java%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%92%8C%E6%96%B0%E8%AF%AD%E6%B3%95/%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6%E4%BD%93%E7%B3%BB.png" class="" title="集合框架体系">
<h1 id="二、Collection中的List"><a href="#二、Collection中的List" class="headerlink" title="二、Collection中的List"></a>二、Collection中的List</h1><h1 id="三、Collection中的set"><a href="#三、Collection中的set" class="headerlink" title="三、Collection中的set"></a>三、Collection中的set</h1>
        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/" rel="tag">学习总结</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-String、StringBuffer、StringBuilder区别" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2022/09/05/String%E3%80%81StringBuffer%E3%80%81StringBuilder%E5%8C%BA%E5%88%AB/">String、StringBuffer、StringBuilder区别</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2022-09-05T10:01:24.000Z" itemprop="datePublished">2022年09月05日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/Java%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF/">Java核心技术</a>
  </div>

      
      
<a href="/blog/2022/09/05/String%E3%80%81StringBuffer%E3%80%81StringBuilder%E5%8C%BA%E5%88%AB/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="String"><a href="#String" class="headerlink" title="String"></a>String</h1><p>典型的 Immutable 类，被声明成为 final class，所有属性也都是 final 的。<br>也由于它的不可变性，类似拼接、裁剪字符串等动作，都会产生新的 String 对象。<br>由于字符串操作的普遍性，所以相关操作的效率往往对应用性能有明显影响。</p>
<h1 id="StringBuffer"><a href="#StringBuffer" class="headerlink" title="StringBuffer"></a>StringBuffer</h1><p>为解决上面提到拼接产生太多中间对象的问题而提供的一个类，<br>我们可以用 append 或者 add 方法，把字符串添加到已有序列的末尾或者指定位置。<br>StringBuffer 本质是一个线程安全的可修改字符序列，它保证了线程安全，也随之带来了额外的性能开销，<br>所以除非有线程安全的需要，不然还是推荐使用它的后继者，也就是 StringBuilder。</p>
<h1 id="StringBuilder"><a href="#StringBuilder" class="headerlink" title="StringBuilder"></a>StringBuilder</h1><p>在能力上和 StringBuffer 没有本质区别，但是它去掉了线程安全的部分，有效减小了开销，是绝大部分情况下进行字符串拼接的首选。</p>

        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/" rel="tag">学习总结</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>


  <article id="post-Java中的异常处理" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="p-name article-title" href="/blog/2022/08/19/Java%E4%B8%AD%E7%9A%84%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86/">Java中的异常处理</a>
    </h1>
  


      </header>
    
    <div class="article-meta">
      
      <span class="article-date">
  <i class="fa fa-date"></i>
  <time class="dt-published" datetime="2022-08-19T07:01:11.000Z" itemprop="datePublished">2022年08月19日</time>
</span>
      
  <div class="article-category">
    <i class="fa fa-classify"></i>
    <a class="article-category-link" href="/blog/categories/Java/">Java</a>
  </div>

      
      
<a href="/blog/2022/08/19/Java%E4%B8%AD%E7%9A%84%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86/#comments" class="article-comment-link">
  
  <i class="fa fa-commt"></i>
  留言
</a>


    </div>
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="一、异常和-try-catch"><a href="#一、异常和-try-catch" class="headerlink" title="一、异常和 try catch"></a>一、异常和 try catch</h1><h2 id="1-1-初识异常"><a href="#1-1-初识异常" class="headerlink" title="1.1 初识异常"></a>1.1 初识异常</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">class Demo&#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        // &gt;&gt; TODO try 语句中如果发生了异常（Exception），那么程序会跳转到catch语句。</span><br><span class="line">        // &gt;&gt; TODO Java会将异常相关信息封装在一个异常类的实例中，ex是指向这个异常实例的引用</span><br><span class="line">        // &gt;&gt; TODO &quot;处理&quot;最简单的方法，就是调用printStackTrace将异常信息输出到控制台</span><br><span class="line">        // &gt;&gt; TODO catch语句执行完毕，程序会继续向下顺序执行</span><br><span class="line">        try &#123;</span><br><span class="line">            int[] arr = new int[1];</span><br><span class="line">            arr[1] = 9;</span><br><span class="line">        &#125; catch (Exception ex) &#123;</span><br><span class="line">            ex.printStackTrace(); // java.lang.ArrayIndexOutOfBoundsException: 1</span><br><span class="line">        &#125;</span><br><span class="line">        try &#123;</span><br><span class="line">            String str = &quot;&quot;;</span><br><span class="line">            str.substring(9, 10);</span><br><span class="line">        &#125; catch (Exception ex) &#123;</span><br><span class="line">            ex.printStackTrace(); // java.lang.StringIndexOutOfBoundsException: String index out of range: 10</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(&quot;程序执行结束&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="1-2-异常的分类"><a href="#1-2-异常的分类" class="headerlink" title="1.2 异常的分类"></a>1.2 异常的分类</h2><h3 id="1-2-1-按照异常的继承关系分类"><a href="#1-2-1-按照异常的继承关系分类" class="headerlink" title="1.2.1 按照异常的继承关系分类"></a>1.2.1 按照异常的继承关系分类</h3><ul>
<li>异常也是 Java 中的类</li>
<li>所有异常的父类：Throwable</li>
<li>两类异常：Error 和 Exception  <img src="/blog/2022/08/19/Java%E4%B8%AD%E7%9A%84%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86/Throwable.png" class="" title="Throwable">  </li>
<li><em>idea小技巧</em>*<br>按两下Shift，输入Throwable，找到该类文件，然后菜单栏Navigate-&gt;Type Hierarchy<h3 id="1-2-2-按照处理方式不同分类"><a href="#1-2-2-按照处理方式不同分类" class="headerlink" title="1.2.2 按照处理方式不同分类"></a>1.2.2 按照处理方式不同分类</h3></li>
<li>checked exception：语法要求必须要用 try catch 或者 throws 语句处理的异常</li>
<li>unchecked exception：语法不要求一定要用 try catch 或者 throws 语句处理的异常</li>
<li>Error 和 RuntimeException 是 unchecked exception的父类。我们一般使用 RuntimeException<br>怎么理解RuntimeException 是 unchecked exception的父类？<br><code>int num = 5/0; // 会报ArithmeticException，而ArithmeticException继承RuntimeException，此异常不强制处理</code>  <h3 id="1-2-3-小题目"><a href="#1-2-3-小题目" class="headerlink" title="1.2.3 小题目"></a>1.2.3 小题目</h3>NoClassDefFoundError 和 ClassNotFoundException 有什么区别？<br>直观区别：一个是异常，一个是错误  </li>
</ul>
<ol>
<li>ClassNotFoundException和NoClassDefFoundError都发生在JVM在classpath下找不到所需的类时</li>
<li>ClassNotFoundException<br>当应用尝试在类路径中用全限量名去加载某个类时，如果找你不到它的定义就会报CLassNotFoundException。它是一个可检测异常.使用反射时，要注意这个异常。    <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line">class Demo&#123;</span><br><span class="line">    public static void main(String[] args) throws ClassNotFoundException &#123;</span><br><span class="line">        Class.forName(&quot;com.test.api&quot;); // 此类不存在，就会报ClassNotFoundException</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">```  </span><br><span class="line">3. NoClassDefFoundError  </span><br><span class="line">NoClassDefFoundError是一种致命错误。  </span><br><span class="line">当JVM尝试通过new关键字创建一个类实例或者方法调用来加载一个类时找不到这个类的定义就会出现这个错误。  </span><br><span class="line">通常是编译时正常编译，但是运行时找不到这个类.  </span><br><span class="line">通常发生在执行动态代码块或者初始化静态字段时报了异常，从而导致类初始化失败而引发NoClassDefFoundError  </span><br><span class="line">**如下代码就是在初始化静态字段时报了异常**    </span><br><span class="line">```shell</span><br><span class="line">public class ClassWithInitErrors &#123;</span><br><span class="line">    static int data = 1 / 0;</span><br><span class="line">&#125;</span><br><span class="line">public class NoClassDefFoundErrorDemo &#123;</span><br><span class="line">    public ClassWithInitErrors getClassWithInitErrors() &#123;</span><br><span class="line">        ClassWithInitErrors test;</span><br><span class="line">        try &#123;</span><br><span class="line">            test = new ClassWithInitErrors();</span><br><span class="line">        &#125; catch (Throwable t) &#123;</span><br><span class="line">            System.out.println(t);</span><br><span class="line">        &#125;</span><br><span class="line">        test = new ClassWithInitErrors();</span><br><span class="line">        return test;</span><br><span class="line">    &#125;</span><br><span class="line">    public static void main(String[] args)&#123;</span><br><span class="line">        NoClassDefFoundErrorDemo noClassDefFoundErrorDemo = new NoClassDefFoundErrorDemo();</span><br><span class="line">        noClassDefFoundErrorDemo.getClassWithInitErrors();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">```  </span><br><span class="line">4. 总结  </span><br><span class="line">ClassNotFoundException与NoClassDefException核心区别是，前者强调运行时无法匹配到指定参数名称的类，后者强调编译时没问题，运行时却无法实例化一个类。</span><br><span class="line">最常见的解决方法是检查是否依赖了相关包或者相关包是否有冲突。  </span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># 1.3 异常使用基本原则</span></span></span><br><span class="line">1. 尽量不要捕获类似 Exception 这样的通用异常，而是应该捕获特定异常</span><br><span class="line">2. 不要生吞（swallow）异常。</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># 1.4 异常的传递</span></span></span><br><span class="line">* Java 异常的的归宿：要么沿着方法调栈顺序一路抛，最终造成当前线</span><br><span class="line">程出错退出，要么被 catch 住</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># 1.5 自定义异常</span></span></span><br><span class="line">* 异常最重要的信息：类型，错误信息和出错时的调用栈</span><br><span class="line">```shell</span><br><span class="line">public class MyException extends Exception&#123;</span><br><span class="line">    public MyException()&#123;</span><br><span class="line">    &#125;</span><br><span class="line">    public MyException(String message)&#123;</span><br><span class="line">        super(message);</span><br><span class="line">    &#125;</span><br><span class="line">    public MyException(String message, Throwable cause)&#123;</span><br><span class="line">        super(message, cause);</span><br><span class="line">    &#125;</span><br><span class="line">    public MyException(Throwable cause)&#123;</span><br><span class="line">        super(cause);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="1-6-try-catch-finally-语句"><a href="#1-6-try-catch-finally-语句" class="headerlink" title="1.6 try catch finally 语句"></a>1.6 try catch finally 语句</h2><h3 id="1-6-1-catch-多种异常"><a href="#1-6-1-catch-多种异常" class="headerlink" title="1.6.1 catch 多种异常"></a>1.6.1 catch 多种异常</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">try &#123;</span><br><span class="line">    ...;</span><br><span class="line">    // &gt;&gt; TODO 如果一个方法抛出多种异常，可以针对多个类型有多种catch语语句</span><br><span class="line">&#125; catch (ClassNotFoundException e) &#123;</span><br><span class="line">    e.printStackTrace();</span><br><span class="line">&#125; catch (IOException e) &#123;</span><br><span class="line">    e.printStackTrace();</span><br><span class="line">&#125;</span><br><span class="line">```  </span><br><span class="line">```shell</span><br><span class="line">try &#123;</span><br><span class="line">    ...;</span><br><span class="line">    // &gt;&gt; TODO 如果捕获了不同类型的异常，但是处理方式一样，可以用简化模式</span><br><span class="line">&#125; catch (ClassNotFoundException | IOException e) &#123;</span><br><span class="line">    e.printStackTrace();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1-6-2-try-finally"><a href="#1-6-2-try-finally" class="headerlink" title="1.6.2 try finally"></a>1.6.2 try finally</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"> public static void main(String[] args) &#123;</span><br><span class="line">        System.out.println(withFinally());</span><br><span class="line">        System.out.println(VAL);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">private static int withFinally() &#123;</span><br><span class="line">    int len = 0;</span><br><span class="line">    try &#123;</span><br><span class="line">//            String s = null; </span><br><span class="line">        String s = &quot;abc&quot;;</span><br><span class="line">        return s.length();</span><br><span class="line">    &#125; finally &#123;</span><br><span class="line">        // &gt;&gt; TODO 可以认为finally语句会在方法返回后，后面的方法开始前，会在return语句后</span><br><span class="line">        // &gt;&gt; TODO 无论是因为return结束还是因为异常结束，finally语句都会执行</span><br><span class="line">        System.out.println(&quot;执行finally语句&quot;);</span><br><span class="line">           &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1-6-3-try-catch-finally"><a href="#1-6-3-try-catch-finally" class="headerlink" title="1.6.3 try catch finally"></a>1.6.3 try catch finally</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">private static int VAL = 0;</span><br><span class="line"></span><br><span class="line">public static void main(String[] args) &#123;</span><br><span class="line">    System.out.println(withFinally());</span><br><span class="line">    System.out.println(VAL);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">private static int withFinally() &#123;</span><br><span class="line">    int len = 0;</span><br><span class="line">    try &#123;</span><br><span class="line">        String s = null;</span><br><span class="line">//            String s = &quot;abc&quot;;</span><br><span class="line">        return s.length();</span><br><span class="line">    &#125; catch (Exception ex) &#123;</span><br><span class="line">        // &gt;&gt; TODO 异常的处理：在有返回值的情况下，返回一个特殊的值，代表情况不对，有异常</span><br><span class="line">        len = -1;</span><br><span class="line">        System.out.println(&quot;执行catch里的return语句&quot;);</span><br><span class="line">        return len;</span><br><span class="line">    &#125; finally &#123;</span><br><span class="line">        // &gt;&gt; TODO 可以认为finally语句会在方法返回后，后面的方法开始前，会在return语句后</span><br><span class="line">        // &gt;&gt; TODO 无论是因为return结束还是因为异常结束，finally语句都会执行</span><br><span class="line">        System.out.println(&quot;执行finally语句&quot;);</span><br><span class="line">        // &gt;&gt; TODO finally里最好不要有return语句,会打乱exception的传递</span><br><span class="line">//            return -2;</span><br><span class="line"></span><br><span class="line">        // &gt;&gt; TODO finally里给return用的变量值赋值没用</span><br><span class="line">//            len = -2;</span><br><span class="line"></span><br><span class="line">        VAL = 999;</span><br><span class="line">        System.out.println(&quot;finally语句执行完毕&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1-6-4-自动回收资源的-try-语句-try-with-resource"><a href="#1-6-4-自动回收资源的-try-语句-try-with-resource" class="headerlink" title="1.6.4 自动回收资源的 try 语句(try-with-resource)"></a>1.6.4 自动回收资源的 try 语句(try-with-resource)</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">public class MyAutoClosableResource implements AutoCloseable &#123;</span><br><span class="line">    private String resName;</span><br><span class="line">    private int counter;</span><br><span class="line">    public MyAutoClosableResource(String resName) &#123;</span><br><span class="line">        this.resName = resName;</span><br><span class="line">    &#125;</span><br><span class="line">    public String read() throws IOException &#123;</span><br><span class="line">        counter++;</span><br><span class="line">        if (Math.random() &gt; 0.1) &#123;</span><br><span class="line">            return &quot;You got lucky to read from &quot; + resName + &quot; for &quot; + counter + &quot; times...&quot;;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            throw new IOException(&quot;resource不存在哦&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    @Override</span><br><span class="line">    public void close() throws Exception &#123;</span><br><span class="line">        System.out.println(&quot;资源释放了:&quot; + resName);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">public class TryWithResource &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        try (</span><br><span class="line">             MyAutoClosableResource res1 = new MyAutoClosableResource(&quot;res1&quot;);</span><br><span class="line">             MyAutoClosableResource res2 = new MyAutoClosableResource(&quot;res2&quot;)</span><br><span class="line">        ) &#123;</span><br><span class="line">            while (true) &#123;</span><br><span class="line">                System.out.println(res1.read());</span><br><span class="line">                System.out.println(res2.read());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">```    </span><br><span class="line">以上代码运行结果  </span><br><span class="line">&#123;% asset_img TryWithResource.png TryWithResource %&#125;  </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># 1.7 Java 中的常见异常</span></span></span><br><span class="line">* NullPointerException</span><br><span class="line">* IndexOutOfBoundsException</span><br><span class="line">* ClassCastException</span><br><span class="line">```shell</span><br><span class="line">class Animal&#123;</span><br><span class="line">    public void run()&#123;</span><br><span class="line">        System.out.println(&quot;动物跑&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">class Dog extends Animal&#123;</span><br><span class="line">    @Override</span><br><span class="line">    public void run() &#123;</span><br><span class="line">        System.out.println(&quot;狗跑&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static void main(String[] args)&#123;</span><br><span class="line">        Animal animal = new Animal();</span><br><span class="line">        Dog dog = (Dog) animal; // 父类引用指向的对象的类型不是子类的时候强制转换将产生java.lang.ClassCastException异常</span><br><span class="line">        dog.run();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<ul>
<li>ClassNotFoundException</li>
<li>IOException</li>
</ul>

        
        
          <blockquote id="copyright">
              <p>原文链接: <a href="http://haohongbin.gitee.io/blog/index.html">http://haohongbin.gitee.io/blog/index.html</a></p>
              <p>版权声明: 转载请注明出处.</p>
          </blockquote>
        
      
    </div>
    <footer class="article-footer">
      
        <div class="article-tag-wrap">
          

          
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/" rel="tag">学习总结</a></li></ul>

          
    <div class="social-share">
      <span>分享到:</span>
    </div>



        </div>
      
      
      
    </footer>
  </div>
</article>



    <nav id="page-nav">

<span class="page-number current">1</span><a class="page-number" href="/blog/page/2/">2</a><a class="extend next" rel="next" href="/blog/page/2/">下一页</a>
</nav>


</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-posts"></i> 最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/blog/2023/03/14/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E5%88%97%E8%A1%A8%E5%92%8C%E5%85%83%E7%BB%84/">(no title)</a>
          </li>
        
          <li>
            <a href="/blog/2023/03/09/Java%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95Mock%E7%A5%9E%E5%99%A8/">Java单元测试Mock神器</a>
          </li>
        
          <li>
            <a href="/blog/2023/02/21/Pytest%E6%89%A7%E8%A1%8C%E7%94%A8%E4%BE%8B%E7%9A%84%E5%A4%9A%E7%A7%8D%E6%96%B9%E5%BC%8F/">Pytest执行用例的多种方式</a>
          </li>
        
          <li>
            <a href="/blog/2023/02/20/SQL%E6%9F%A5%E8%AF%A2%E5%9C%BA%E6%99%AF/">SQL查询场景</a>
          </li>
        
          <li>
            <a href="/blog/2023/01/18/MySQL%E5%91%BD%E4%BB%A4%E6%89%8B%E5%86%8C/">MySQL命令手册</a>
          </li>
        
      </ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-tag"></i> 标签云</h3>
    <div class="widget tagcloud">
      <a href="/blog/tags/MySQL/" style="font-size: 15px;">MySQL</a> <a href="/blog/tags/%E5%88%86%E4%BA%AB/" style="font-size: 15px;">分享</a> <a href="/blog/tags/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/" style="font-size: 10px;">单元测试</a> <a href="/blog/tags/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/" style="font-size: 20px;">学习总结</a> <a href="/blog/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/" style="font-size: 10px;">自动化</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-classify"></i> 分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/blog/categories/Java/">Java</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/Java%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF/">Java核心技术</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/hexo%E5%8D%9A%E5%AE%A2/">hexo博客</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/vim/">vim</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/%E5%90%8E%E7%AB%AF/">后端</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/%E6%B5%8B%E8%AF%95/">测试</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/%E6%B5%8B%E8%AF%95%E8%BF%9B%E9%98%B6/">测试进阶</a><span class="category-list-count">1</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-archive"></i> 归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/blog/archives/2023/">2023年</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/blog/archives/2022/">2022年</a><span class="archive-list-count">10</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title"><i class="fa fa-tag"></i> 标签</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/blog/tags/MySQL/" rel="tag">MySQL</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/blog/tags/%E5%88%86%E4%BA%AB/" rel="tag">分享</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/blog/tags/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/" rel="tag">单元测试</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/blog/tags/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/" rel="tag">学习总结</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/blog/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/" rel="tag">自动化</a><span class="tag-list-count">1</span></li></ul>
    </div>
  </div>


  
    

  
</aside>
        
      </div>
      <a id="totop" href="#top"></a>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      <p>
        <a href="/blog/sitemap.xml">网站地图</a>
        <span> | </span><a href="/blog/atom.xml">订阅本站</a>
        <span> | </span><a href="/blog/about/">联系博主</a>
      </p>
      
        <p>
          <i class="fa fa-visitors"></i>
          <i id="busuanzi_container_site_uv"><i id="busuanzi_value_site_uv"></i></i>
          ，
          <i class="fa fa-views"></i>
          <i id="busuanzi_container_site_pv"><i id="busuanzi_value_site_pv"></i></i>
        </p>
      
      <p>
        <span>Copyright &copy; 2023 奉孝.</span>
        <span>Theme by <a href="https://github.com/chaooo/hexo-theme-BlueLake/" target="_blank">BlueLake.</a></span>
        <span>Powered by <a href="https://hexo.io/" target="_blank">Hexo.</a></span>
      </p>
    </div>
  </div>
</footer>

    </div>
  </div>
  
<script src="/blog/js/jquery-3.4.1.min.js"></script>


<script src="/blog/js/search.json.js"></script>


  
<script src="/blog/fancybox/jquery.fancybox.min.js"></script>




<script src="/blog/js/script.js"></script>






  
<script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>








  



</body>
</html>